#include "StdAfx.h"
#include ".\apSSEngine1.h"
#include "apFileLog.h"
#include "apfastTiming.h"

static const NChar * components = N_T("SentiSight");

apSSEngine1::apSSEngine1(void)
:m_hSE(NULL), m_hModel(NULL), m_hBuffer(NULL),
m_inited(false), m_BGlearned(false),
m_llRecCnt(0), m_llHitCnt(0)
{
}

apSSEngine1::~apSSEngine1(void)
{
	if(m_inited)
		Close();
}

void apSSEngine1::Close()
{
	if (m_hBuffer) 
		NObjectFree(m_hBuffer);
	if (m_hModel) 
		NObjectFree(m_hModel);
	if (m_hSE) 
		NObjectFree(m_hSE);

	NResult result1 = NLicenseReleaseComponents(components);
	if (NFailed(result1))
	{
		apLog::print(0, apLog::error, "NLicenseReleaseComponents() failed, result = %d\n",
			result1);
	}

	NCoreOnExitEx(NFalse);
}

void apSSEngine1::DumpInfo()
{
	bool ret;

	int			lrnMode;
	int			learn_type, rec_type;
	int			rec_speed;
	int			rec_useTracking;
	double		rec_thr;
	double		lrn_res_fac = 0.0f;
	int			thread_num;

	ret = GetThreadNum(&thread_num);
	ret = GetLrnMode(&lrnMode);
	ret = GetFeaType(0, &learn_type);
	ret = GetFeaType(1, &rec_type);
	ret = GetRecSpeed(&rec_speed);
	ret = GetRecUseTracking(&rec_useTracking);
	ret = GetRecThr(&rec_thr);
	//ret = GetLrnRescaleFactor(&lrn_res_fac);

	apLog::print(0, apLog::info, "SentiSight engine info:\n"
		"thread number %d\n"
		"learn mode: %d, learn feature type: %d, "
		"recognize feature type: %d, "
		"recognize speed: %d, use tracking %d, rec thr %.f, learn res factor %.3f",
		thread_num, 
		lrnMode, learn_type, 
		rec_type, rec_speed, rec_useTracking, rec_thr,
		lrn_res_fac);
}

bool apSSEngine1::Init()
{
	int argc = 0;
	NChar **argv = NULL;
	NBool available;
	NResult result;
	bool ret;

	result = NCoreOnStart();
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "SE engine: Failed to verify license");
		return false;
	}

	result = NLicenseObtainComponents(N_T("/local"), N_T("5000"), components, &available);
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "NLicenseObtainComponents() failed, result = %d\n",
			result);
		return false;
	}

	const NChar * components = N_T("SentiSight");

	// A m_hSEEngine handle must be allocated. This handle will be used in the whole object learning process
	result = SECreate(&m_hSE);
	if(NFailed(result))
	{
		if(result == N_E_NOT_SUPPORTED)
		{
			apLog::print(0, apLog::error, "your processor does not support necessary SSE instructions");
		}
		else
		{
			apLog::print(0, apLog::error, "failed to initialize SentiSight (result = %d)", result);
		}

		return false;
	}

	DumpInfo();
	//ret = SetLrnMode(1);
	//ret = SetRecSpeed(0);
	//ret = SetRecUseTracking(1);
	ret = SetRecThr(1000.0f);
	//ret = SetThreadNum(8);
	DumpInfo();

	m_inited = true;
	return true;
}

bool apSSEngine1::GetFeaType(int is_learn, int *pType)
{
	NResult result;
	NUInt paramId;
	SEFeatureType type;

	if(is_learn > 0)
		paramId = SEP_LRN_FEATURE_TYPE;
	else
		paramId = SEP_REC_FEATURE_TYPE;
	result = NObjectGetParameterEx(m_hSE, paramId, 
		N_TYPE_INT, &type, sizeof(type));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to get feature type (result = %d)\n", result);
		return false;
	}

	*pType = (int)type;
	return true;
}

bool apSSEngine1::SetFeaType(int is_learn, int featype)
{
	NResult result;
	NUInt paramId;
	SEFeatureType type;

	switch(featype)
	{
	case 1:
		type = seftBlob;
		break;
	case 2:
		type = seftShape;
		break;
	case 3:
		type = seftCombined;
		break;
	default:
		apLog::print(0, apLog::error, "unknown feature type input: %d", featype);
		return false;
	}

	if(is_learn > 0)
		paramId = SEP_LRN_FEATURE_TYPE;
	else
		paramId = SEP_REC_FEATURE_TYPE;
	result = NObjectSetParameterEx(m_hSE, paramId, 
		N_TYPE_INT, &type, sizeof(type));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to set feature type (result = %d)\n", result);
		return false;
	}
	
	apLog::print(0, apLog::info, "%s feature type %d setted",
		((is_learn > 0) ? "learn" : "recognize"), featype);
	return true;
}

bool apSSEngine1::GetLrnMode(int *pMode)
{
	NResult result;

	SELrnMode mode;

	result = NObjectGetParameterEx(m_hSE, SEP_LRN_MODE, 
		N_TYPE_INT, &mode, sizeof(mode));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to get learn mode(result = %d)\n", result);
		return false;
	}

	*pMode = (int)mode;
	return true;
}

bool apSSEngine1::SetLrnMode(int mode)
{
	NResult result;

	SELrnMode mode_;

	switch(mode)
	{
	case 0:
		mode_ = selmLowProfile;
		break;
	case 1:
		mode_ = selmHighProfile;
		break;
	case 2:
		mode_ = selmHighProfileEx;
		break;
	default:
		apLog::print(0, apLog::error, "unknown learn mode input: %d", mode);
		return false;
	}

	result = NObjectSetParameterEx(m_hSE, SEP_LRN_MODE, 
		N_TYPE_INT, &mode_, sizeof(mode_));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to set learn mode (result = %d)\n", result);
		return false;
	}

	apLog::print(0, apLog::info, "learn mode %d setted", mode);
	return true;
}

bool apSSEngine1::GetRecSpeed(int *pSpeed)
{
	NResult result;
	NInt val;

	result = NObjectGetParameterEx(m_hSE, SEP_REC_SPEED, 
		N_TYPE_INT, &val, sizeof(val));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to get rec speed(result = %d)\n", result);
		return false;
	}

	*pSpeed = val;
	return true;
}

bool apSSEngine1::SetRecSpeed(int speed)
{
	NResult result;

	if(speed > 256 || speed < 0)
	{
		apLog::print(0 ,apLog::error, "invalid speed value: %d", speed);
		return false;
	}

	//need fix
	result = NObjectSetParameterEx(m_hSE, SEP_REC_SPEED, 
		N_TYPE_INT, &speed, sizeof(N_TYPE_INT));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to set rec speed (result = %d)\n", result);
		return false;
	}

	apLog::print(0, apLog::info, "rec speed %d setted", speed);
	return true;
}

bool apSSEngine1::CreateModel()
{
	NResult result;

	// Now a SentiSightEngine model handle must be allocated. This handle will store information about the model of the object.
	result = SECreateModelEx(m_hSE, 0, &m_hModel);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to create model (result = %d)\n", result);
		return false;
	}

	return true;
}

bool apSSEngine1::GenModel()
{
	NResult result;
	SEStatus status;
	NBool isGeneralized;

	// Generalize learned model.
	result = SELrnGeneralizeModel(m_hSE, m_hModel, &status);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to generalize model (result = %d)", result);
		return false;
	}

	if (status == sesSucceeded)
	{
		apLog::print(0, apLog::info, "generalization succeeded");
	}
	else if (status == sesModelIsEmpty)
	{
		apLog::print(0, apLog::warning, "warning: input model is empty");
		return false;
	}
	else if (status != sesSucceeded)
	{
		apLog::print(0, apLog::warning, "model is not generalized, status: %d", status);
		return false;
	}

	// Save model to buffer
	result = NObjectSaveToMemoryN(m_hModel, 0, &m_hBuffer);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "NObjectSaveToMemoryN() failed (result = %d)", result);
		return false;
	}

	result = SEModelIsGeneralized(m_hModel, &isGeneralized);
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to check whether model is generalized (result = %d)", result);
		return false;
	}

	if (!isGeneralized)
	{
		apLog::print(0, apLog::error, "specified model is not generalized. only generalized models can be added to recognition");
		return false;
	}

	return true;
}

bool apSSEngine1::LoadModel_mem()
{
	void *modelId = NULL;
	NResult result;
	SEStatus status;

	// Model should be unique for each model
	modelId = (void *)(NSizeType)1;//hard code

	// Add model to SentiSight
	result = SERecAddModelEx(m_hSE, m_hModel, modelId, &status);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "Failed adding model to SentiSight (result = %d)", result);
		return false;
	}
	if (status != sesSucceeded)
	{
		apLog::print(0, apLog::error, "failed to add model. Reason: %d", status);
		return false;
	}
	
	return true;
}

bool apSSEngine1::GenShape(HSEShape *phShape, NPointD *points, int pointCnt)
{
	NResult result;
	NBool bValid;
	NInt count;

	result = SEShapeCreate(phShape);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to create shape (result = %d)", result);
		return false;
	}

	for(int i=0 ; i<pointCnt ; i++)
	{
		result = SEShapeAddPointEx(*phShape, &points[i]);
		if(NFailed(result))
		{
			apLog::print(0, apLog::error, "failed to add point (result = %d)", result);
			return false;
		}
	}

	result = SEShapeIsValid(*phShape, &bValid);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to is valid(result = %d)", result);
		SEShapeClearPoints(*phShape);
		return false;
	}
	if(!bValid)
		apLog::print(0, apLog::warning, "input shape is invalid %d", bValid);

	result = SEShapeGetPointCount(*phShape, &count);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to get point count(result = %d)", result);
		SEShapeClearPoints(*phShape);
		return false;
	}
	apLog::print(0, apLog::info, "input shape point number: %d", count);
	if(count != pointCnt)
	{
		apLog::print(0, apLog::error, "point count mismatch");
		SEShapeClearPoints(*phShape);
		return false;
	}

	return true;
}
bool apSSEngine1::Learn_pic_mask(const char *srcFilename,
								 const char *maskFilename, HBITMAP *phBmp)
{
	bool ret = false;
	HNImage hImage = NULL;
	HNImage hMask  = NULL;
	NResult result = N_OK;

	// Create image from file
	result = NImageCreateFromFileEx((NChar *)srcFilename, NULL, 0, NULL, &hImage);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to open image (result = %d)", result);
		return false;
	}
	if(NULL != maskFilename)
	{
		result = NImageCreateFromFileEx((NChar *)maskFilename, NULL, 0, NULL, &hMask);
		if(NFailed(result))
		{
			apLog::print(0, apLog::error, "failed to open image (result = %d)", result);
			return false;
		}
	}

	ret = Learn_img_mask(hImage, hMask, phBmp);
	
	NObjectFree(hImage);
	hImage = NULL;
	if(hMask)
	{
		NObjectFree(hMask);
		hMask = NULL;
	}

	return ret;
}

bool apSSEngine1::Learn_pic_shape(const char *srcFilename,
					 HSEShape *hShapes, int shapeCnt, HBITMAP *phBmp)
{
	bool ret = false;
	NResult result = N_OK;
	HNImage hImage = NULL;

	// Create image from file
	result = NImageCreateFromFileEx((NChar *)srcFilename, NULL, 0, NULL, &hImage);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to open image (result = %d)", result);
		return false;
	}

	ret = Learn_img_shape(hImage, hShapes, shapeCnt, phBmp);

	NObjectFree(hImage);
	hImage = NULL;

	return ret;
}

bool apSSEngine1::Learn_img_mask(HNImage hImage, HNImage hMask, HBITMAP *phBmp)
{
	bool		ret				= false;
	HNImage		hMaskLocal		= NULL;
	HNImage		hConvertedMask	= NULL;
	HNImage		hBackground		= NULL;
	HNImage		hSegmentedFrame = NULL;
	NBool		isForeground;
	NResult		result			= N_OK;
	NUInt		refId;
	SEStatus	ses;

	if(NULL == hMask)
	{
		// separates foreground (the object) from background
		result = SESepSeparate(m_hSE, hImage, &hMaskLocal, &hBackground, &hSegmentedFrame, &isForeground);
		if(NFailed(result))
		{
			apLog::print(0, apLog::error, "failed to separate foreground (result = %d)", result);
			return false;
		}

		// If foreground object found, save it as image and mask
		if(!isForeground)
		{
			apLog::print(0, apLog::warning, "failed to get foreground");
			return false;//need fix
		}

		// Transform colored image to grayscale
		result = NImageToGrayscale(hMaskLocal, (HNGrayscaleImage *)&hConvertedMask);
		if(NFailed(result))
		{
			apLog::print(0, apLog::error, "failed to transform image to grayscale (result = %d)", result);
			NObjectFree(hMask);
			return false;
		}
		if(phBmp != NULL)
			NImageToHBitmap(/*hSegmentedFrame*/hMaskLocal, phBmp);
		NImageSaveToFile(hMaskLocal, "d:\\mask_001.bmp", NULL);
	}
	else
	{
		if(phBmp != NULL)
			NImageToHBitmap(hMask, phBmp);
	}

	apHiResElapsedTime tick;
	tick.reset();
	// Add image to model
	if(NULL == hMask)
	{
		result = SELrnAddToModelEx(m_hSE, m_hModel, hImage, 1, &hConvertedMask, 
			NULL, &refId, &ses);
	}
	else
	{
		result = SELrnAddToModelEx(m_hSE, m_hModel, hImage, 1, &hMask, 
			NULL, &refId, &ses);
	}

	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to add image to model (result = %d)", result);
		NObjectFree(hMask);
		NObjectFree(hConvertedMask);
		return false;
	}
	apLog::print(0, apLog::info, "add model %d msec", (int)tick.msec());

	if(ses == sesSucceeded)
	{
		apLog::print(0, apLog::info, "model is updated, refId = %d", refId);
		ret = true;//bingo!!!
	}
	else if(ses == sesNothingToLearn)
	{
		apLog::print(0, apLog::info, "model is not updated, nothing to learn");
		ret = true;//bingo!!!
	}
	else if (ses == sesMaskIsEmpty)
	{
		apLog::print(0, apLog::warning, "model is not updated, mask is empty");
	}
	else if (ses == sesShapeNotValid)
	{
		apLog::print(0, apLog::warning, "model is not updated, shape is not valid");
	}
	else if (ses != sesSucceeded)
	{
		apLog::print(0, apLog::warning, "model is not updated, status: %d", ses);
	}

	NObjectFree(hMaskLocal);
	NObjectFree(hConvertedMask);
	return ret;
}


bool apSSEngine1::Learn_img_shape(HNImage hImage, HSEShape *hShapes, int shapeCnt,
								  HBITMAP *phBmp)
{
	bool		ret				= false;
	NResult		result			= N_OK;
	NUInt		refId;
	SEStatus	ses;

	apLog::print(0, apLog::info, "Learn_img_shape: %d", shapeCnt);

	apHiResElapsedTime tick;
	tick.reset();

	// Add image to model
	result = SELrnAddToModelEx(m_hSE, m_hModel, hImage, shapeCnt, NULL, 
		hShapes, &refId, &ses);

	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to add image to model (result = %d)", result);
		return false;
	}
	apLog::print(0, apLog::info, "add model %d msec", (int)tick.msec());

	if(ses == sesSucceeded)
	{
		apLog::print(0, apLog::info, "model is updated, refId = %d", refId);
		ret = true;//bingo!!!
	}
	else if(ses == sesNothingToLearn)
	{
		apLog::print(0, apLog::info, "model is not updated, nothing to learn");
		ret = true;//bingo!!!
	}
	else if (ses == sesMaskIsEmpty)
	{
		apLog::print(0, apLog::warning, "model is not updated, mask is empty");
	}
	else if (ses == sesShapeNotValid)
	{
		apLog::print(0, apLog::warning, "model is not updated, shape is not valid");
	}
	else if (ses != sesSucceeded)
	{
		apLog::print(0, apLog::warning, "model is not updated, status: %d", ses);
	}

	return ret;
}

int apSSEngine1::GetModelSize()
{
	NResult result;
	NSizeType bufferSize;

	result = NBufferGetSize(m_hBuffer, &bufferSize);
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "NBufferGetSize() failed(result = %d)", result);
		return -1;
	}

	return (int)bufferSize;
}

bool apSSEngine1::GetModelData(char *pData)
{
	NResult result;
	void *pBuffer;
	int modelSize;

	modelSize = GetModelSize();
	if(modelSize < 0)
	{
		apLog::print(0, apLog::error, "cannot get model size");
		return false;
	}
	apLog::print(0, apLog::info, "model size %d", modelSize);

	result = NBufferGetPtr(m_hBuffer, &pBuffer);
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "NBufferGetPtr() failed(result = %d)", result);
		return false;
	}

	memcpy(pData, pBuffer, modelSize);
	return true;
}

bool apSSEngine1::LearnBackground_pic(const char* bgFilename, bool *bMore)
{
	NResult result;
	HNImage hImage = NULL;
	bool ret;

	// Create image from file
	result = NImageCreateFromFileEx((NChar *)bgFilename, NULL, 0, NULL, &hImage);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to open background image (result = %d)", result);
		return false;
	}

	ret = LearnBackground_img(hImage, bMore);

	NObjectFree(hImage);
	hImage = NULL;

	return ret;
}

bool apSSEngine1::LearnBackground_img(HNImage hImage, bool *bMore)
{
	NResult result;
	NBool bNMore;
	NUInt width, height;
	NSize frameSize;
	HNImage hBackground = NULL; 

	// Get image width & height
	result = NImageGetWidth(hImage, &width);
	result = NImageGetHeight(hImage, &height);
	frameSize.Width = width;
	frameSize.Height = height;
	SESepSetImageSize(m_hSE, &frameSize);

	result = SESepAccumulateBackground(m_hSE, hImage, &hBackground, &bNMore);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to accumulate background image (result = %d)", result);
		return false;
	}
	if(NTrue == bNMore)
	{
		*bMore = true;
	}
	else
	{
		m_BGlearned = true;
		*bMore = false;
	}

	return true;
}

bool apSSEngine1::RecImage_pic(const char *srcFilename, bool *pIsRec)
{
	NResult result;
	HNImage hImage = NULL;
	bool ret;

	// Create image from file
	result = NImageCreateFromFileEx((NChar *)srcFilename, NULL, 0, NULL, &hImage);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to open image (result = %d)", result);
		return false;
	}

	ret = RecImage_img(hImage, pIsRec);
	NObjectFree(hImage);
	hImage = NULL;
	return ret;
}

bool apSSEngine1::RecImage_img(HNImage hImage, bool *bIsRec)
{
	NResult result;
	NBool isRecognized;

	//for shape
	HSEShape	hShape = NULL;

	apHiResElapsedTime tick;
	tick.reset();
	// Recognize image from SentiSight model
	result = SERecRecognizeImageEx(m_hSE, hImage, &isRecognized);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed recognizing model in frame (result = %d)", result);
		return false;
	}
	apLog::print(0, apLog::info, "recognize #%I64d %d msec", 
		m_llRecCnt, (int)tick.msec());
	if (isRecognized == NTrue)
	{
		apLog::print(0 ,apLog::detail, "hit %I64d in %I64d", m_llHitCnt, m_llRecCnt);
		m_llHitCnt++;
	}

	m_llRecCnt++;
	*bIsRec = isRecognized;
	return true;
}

bool apSSEngine1::GetRecNumber(int *pNum)
{
	NResult result;

	result = SERecGetRecognitionDetailsCount(m_hSE, pNum);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details count (result = %d)", result);
		return false;
	}

	m_recNum = *pNum;
	return true;
}

bool apSSEngine1::GetScore(int index, double *pScore)
{
	NResult result;
	HSERecognitionDetails hRecDetails;

	if(index > m_recNum - 1)
	{
		apLog::print(0, apLog::warning, "HSERecognitionDetails index is overflow");
		return false;
	}

	result = SERecGetRecognitionDetails(m_hSE, index, &hRecDetails);//hard code
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details (result = %d)", result);
		return false;
	}

	result = SERecDetailsGetScore(hRecDetails, pScore);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(Get score) (result = %d)", result);
		return false;
	}
	
	return true;
}

bool apSSEngine1::GetModelId(int index, void **pModelId)
{
	NResult result;
	HSERecognitionDetails hRecDetails;
	const void *modelId = NULL;

	if(index > m_recNum - 1)
	{
		apLog::print(0, apLog::warning, "HSERecognitionDetails index is overflow");
		return false;
	}

	result = SERecGetRecognitionDetails(m_hSE, index, &hRecDetails);//hard code
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details (result = %d)", result);
		return false;
	}

	result = SERecDetailsGetModelId(hRecDetails, &modelId);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(modelId) (result = %d)", result);
		return false;
	}

	*pModelId = (void *)modelId;
	return true;
}


bool apSSEngine1::GetShapePoints(int index, NPointD *points, int *pCount)
{
	NResult					result;
	HSERecognitionDetails	hRecDetails;
	HSEShape				hShape = NULL;
	NInt					pointCount;

	if(index > m_recNum - 1)
	{
		apLog::print(0, apLog::warning, "HSERecognitionDetails index is overflow");
		return false;
	}

	result = SERecGetRecognitionDetails(m_hSE, index, &hRecDetails);//hard code
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details (result = %d)", result);
		return false;
	}

	//process the shape
	result = SERecDetailsGetShape(hRecDetails, &hShape);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(get shape) (result = %d)", result);
		return false;
	}

	result = SEShapeGetPointCount(hShape, &pointCount);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(point count) (result = %d)", result);
		return false;
	}
	if(pointCount > *pCount)
	{
		apLog::print(0, apLog::error, "GetShape points: array size is too small");
		return false;
	}

	apLog::print(0, apLog::detail, "point count %d", pointCount);

	result = SEShapeGetPointsEx(hShape, points, pointCount);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(all points) (result = %d)", result);
		return false;
	}
	for(int i=0;i<pointCount;i++)
	{
		apLog::print(0, apLog::detail, "point[%d] x %.2f, y %.2f",
			i, points[i].X, points[i].Y);
	}

	NObjectFree(hShape);
	*pCount = pointCount; 
	return true;
}


bool apSSEngine1::GetShapeCenter(int index, NPointD *pCenter)
{
	NResult					result;
	HSERecognitionDetails	hRecDetails;
	HSEShape				hShape;

	if(index > m_recNum - 1)
	{
		apLog::print(0, apLog::warning, "HSERecognitionDetails index is overflow");
		return false;
	}

	result = SERecGetRecognitionDetails(m_hSE, index, &hRecDetails);//hard code
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details (result = %d)", result);
		return false;
	}

	result = SERecDetailsGetShape(hRecDetails, &hShape);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(get shape) (result = %d)", result);
		return false;
	}

	result = SEShapeGetCenter(hShape, pCenter);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(center) (result = %d)", result);
		return false;
	}

	NObjectFree(hShape);
	return true;
}

bool apSSEngine1::GetShapeHeading(int index, double *pHeading)
{
	NResult					result;
	HSERecognitionDetails	hRecDetails;
	HSEShape				hShape;

	if(index > m_recNum - 1)
	{
		apLog::print(0, apLog::warning, "HSERecognitionDetails index is overflow");
		return false;
	}

	result = SERecGetRecognitionDetails(m_hSE, index, &hRecDetails);//hard code
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details (result = %d)", result);
		return false;
	}

	result = SERecDetailsGetShape(hRecDetails, &hShape);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(get shape) (result = %d)", result);
		return false;
	}

	result = SEShapeGetHeading(hShape, pHeading);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed getting recognition details(heading) (result = %d)", result);
		return false;
	}

	NObjectFree(hShape);
	return true;
}

bool apSSEngine1::LoadModel_file(const char *modelFilename, int modId)
{
	NResult result;
	NBool isGeneralized;
	void *modelId;
	SEStatus status;
	bool ret;

	if(m_hBuffer)
	{
		NObjectFree(m_hBuffer);
		m_hBuffer = NULL;
	}

	if(m_hModel)
	{
		NObjectFree(m_hModel);
		m_hModel = NULL;
	}

	if (!ReadAllBytesN(modelFilename, &m_hBuffer))
	{
		apLog::print(0, apLog::error, "failed to read model file %s",
			modelFilename);
		return false;
	}

	ret = CreateModel();
	if(!ret)
	{
		apLog::print(0 ,apLog::error, "failed to create model");
		return false;
	}

	result = SEModelLoadFromMemoryN(m_hModel, m_hBuffer, 0, NULL);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed loading model data from buffer (result = %d)", result);
		return false;
	}

	result = SEModelIsGeneralized(m_hModel, &isGeneralized);
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to check whether model is generalized (result = %d)", result);
		return false;
	}

	if (!isGeneralized)
	{
		apLog::print(0, apLog::error, "specified model is not generalized. only generalized models can be added to recognition");
		return false;
	}

	// Model should be unique for each model
	modelId = (void *)(NSizeType)modId;//hard code

	// Add model to SentiSight
	result = SERecAddModelEx(m_hSE, m_hModel, modelId, &status);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "Failed adding model to SentiSight (result = %d)", result);
		return false;
	}
	if (status != sesSucceeded)
	{
		apLog::print(0, apLog::error, "failed to add model. Reason: %d", status);
		return false;
	}

	apLog::print(0, apLog::info, "model file: %s loaded", modelFilename);
	return true;
}

bool apSSEngine1::LearnHolder_pic(const char *srcFilename, HBITMAP *phBmp)
{
	NResult result;
	HNImage hImage = NULL;
	bool ret;

	// Creates (loads) an image from file of specified format
	result = NImageCreateFromFileEx((NChar *)srcFilename, NULL, 0, NULL, &hImage);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to open holder image (result = %d)", result);
		return false;
	}
	ret = LearnHolder_img(hImage, phBmp);

	NObjectFree(hImage);
	hImage = NULL;
	return ret;
}

bool apSSEngine1::LearnHolder_img(HNImage hImage, HBITMAP *phBmp)
{
	NResult result;
	HNImage hMask = NULL, hBackground = NULL, hSegmentedFrame = NULL;
	NBool isForeground;

	// Learn holder
	result = SESepSeparate(m_hSE, hImage, &hMask, &hBackground, 
		&hSegmentedFrame, &isForeground);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to learn holder (result = %d)", result);
		return false;
	}

	if(phBmp != NULL)
		NImageToHBitmap(hSegmentedFrame, phBmp);

	return true;
}

bool apSSEngine1::GenHolder()
{
	NResult result;
	NSizeType bufferSize;
	NSizeType writtenSize;
	NByte * pBuffer;

	// Get model size and allocate buffer
	result = SESepGetObjectModelSizeEx(m_hSE, 0, &bufferSize);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "GenHolder: failed to get model size (result = %d)",
			result);
		return false;
	}

	pBuffer = new NByte[bufferSize];
	if(pBuffer == NULL)
	{
		apLog::print(0, apLog::error, "GenHolder: failed to allocate memory block of size %d", (int)bufferSize);
		return false;
	}

	// Writes a colour model of the object into provided buffer
	result = SESepSaveObjectModelToMemoryEx(m_hSE, pBuffer, bufferSize, 0, &writtenSize);
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "GenHolder: failed to save model to memory (result = %d)", result);
		return false;
	}

	// Resets a color model of the object of foreground/background separation process
	result = SESepResetObjectModel(m_hSE);
	if (NFailed(result))
	{
		delete pBuffer;
		pBuffer = NULL;
		apLog::print(0, apLog::error, "GenHolder: failed to reset model (result = %d)", result);
		return false;
	}

	// Sets a colour model of the holder to be used in foreground/background separation process	
	result = SESepLoadHolderModelFromMemoryEx(m_hSE, pBuffer, bufferSize, 0, NULL);
	delete pBuffer;
	pBuffer = NULL;
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "GenHolder: failed to load holder from memory (result = %d)", result);
		return false;
	}

	return true;
}

bool apSSEngine1::ReadAllBytes(const NChar * szFileName, NByte ** ppBuffer, NSizeType * pSize)
{
	FILE *fp;
	NSizeType bufferSize;
	NSizeType bufferRead;
	NByte * buffer;
	NResult ret;

	fp = fopen(szFileName, "rb");
	if (!fp)
	{
		return false;
	}
	fseek(fp, 0, SEEK_END);
	bufferSize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	ret = NAlloc(bufferSize * sizeof(NByte), (void **)&buffer);
	if (NFailed(ret))
	{
		apLog::print(0, apLog::error, "NAlloc() failed, error %d", ret);
		return false;
	}
	bufferRead = fread(buffer, sizeof(NByte), bufferSize, fp);
	fclose(fp);

	if (bufferRead != bufferSize)
	{
		NFree(buffer);
		return false;
	}

	*ppBuffer = buffer;
	*pSize = bufferSize;

	return true;
}

bool apSSEngine1::ReadAllBytesN(const NChar * szFileName, HNBuffer * phBuffer)
{
	NSizeType bufferSize;
	NByte *buffer = NULL;
	NResult ret;

	if (!ReadAllBytes(szFileName, &buffer, &bufferSize))
		return false;

	ret = NBufferCreateFromPtr(buffer, bufferSize, NTrue, phBuffer);
	if(NFailed(ret))
	{
		NFree(buffer);
		apLog::print(0, apLog::error, "NBufferCreateFromPtr() failed, error %d", ret);
		return false;
	}

	return true;
}

bool apSSEngine1::ResetBackground()
{
	NResult result;

	result = SESepResetBackgroundModel(m_hSE);
	if (NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to reset background model (result = %d)", result);
		return false;
	}

	return true;
}

void apSSEngine1::GetRecStat()
{
	apLog::print(0, apLog::info, "total input frame %I64d, hit %I64d, correct pct %.2f%%", 
		m_llRecCnt, m_llHitCnt, (double)m_llHitCnt * (double)100.f/ (double)m_llRecCnt);
}

bool apSSEngine1::RemoveModel(int modId)
{
	NResult result;

	result = SERecRemoveModel(m_hSE, (void *)modId);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to remove model(result = %d)", result);
		return false;
	}

	return true;
}

bool apSSEngine1::RemoveAllModel()
{
	NResult result;

	result = SERecRemoveAllModels(m_hSE);
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to remove all models(result = %d)", result);
		return false;
	}

	return true;
}

bool apSSEngine1::SetRecThr(double val)
{
	NResult result;

	result = NObjectSetParameterEx(m_hSE, SEP_REC_THRESHOLD, 
		N_TYPE_DOUBLE, &val, sizeof(NDouble));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to set rec threshold(result = %d)", result);
		return false;
	}

	apLog::print(0, apLog::info, "set rec threshold to %d", val);
	return true;
}

bool apSSEngine1::GetRecThr(double *pVal)
{
	NResult result;

	result = NObjectGetParameterEx(m_hSE, SEP_REC_THRESHOLD, 
		N_TYPE_DOUBLE, pVal, sizeof(NDouble));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to get rec threshold(result = %d)", result);
		return false;
	}

	return true;
}

bool apSSEngine1::SetRecUseTracking(int val)
{
	NResult result;
	NBool bTracking;

	if(val > 0)
		bTracking = NTrue;
	else
		bTracking = NFalse;

	result = NObjectSetParameterEx(m_hSE, SEP_REC_USE_TRACKING, 
		N_TYPE_BOOL, &bTracking, sizeof(NBool));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to set rec use tracking(result = %d)", result);
		return false;
	}

	apLog::print(0, apLog::info, "set rec use tracking to %d", val);
	return true;
}

bool apSSEngine1::GetRecUseTracking(int *pVal)
{
	NResult result;
	NBool bTracking;

	result = NObjectGetParameterEx(m_hSE, SEP_REC_USE_TRACKING, 
		N_TYPE_BOOL, &bTracking, sizeof(NBool));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to get rec use tracking(result = %d)", result);
		return false;
	}

	if(NTrue == bTracking)
		*pVal = 1;
	else
		*pVal = 0;

	return true;
}

bool apSSEngine1::SetRecImgRescaleFac(double val)
{
	return true;
}

bool apSSEngine1::GetRecImgRescaleFac(double pVal)
{
	return true;
}

bool apSSEngine1::SetRecShapeScalingLvl(int val)
{
	return true;
}

bool apSSEngine1::GetRecShapeScalingLvl(int pVal)
{
	return true;
}

bool apSSEngine1::SetRecThreads(int val)
{
	return true;
}

bool apSSEngine1::GetRecThreads(int *pVal)
{
	return true;
}

bool apSSEngine1::SetLrnShapeScalingLvl(int val)
{
	return true;
}

bool apSSEngine1::GetLrnShapeScalingLvl(int *pVal)
{
	return true;
}

bool apSSEngine1::SetLrnRescaleFactor(double factor)
{
	NResult result;

	result = NObjectSetParameterEx(m_hSE, SEP_LRN_IMG_RESCALE_FACTOR, 
		N_TYPE_DOUBLE, &factor, sizeof(N_TYPE_DOUBLE));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to set learn rescale factor(result = %d)", result);
		return false;
	}
	
	apLog::print(0, apLog::info, "learn rescale factor set to %.3f", factor);
	return true;
}

bool apSSEngine1::GetLrnRescaleFactor(double *pVal)
{
	NResult result;

	result = NObjectGetParameterEx(m_hSE, SEP_LRN_IMG_RESCALE_FACTOR, 
		N_TYPE_DOUBLE, (void *)pVal, sizeof(N_TYPE_DOUBLE));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to get learn rescale factor(result = %d)", result);
		return false;
	}

	return true;
}

bool apSSEngine1::SetThreadNum(int num)
{
	NResult result;

	result = NObjectSetParameterEx(m_hSE, SEP_NUMBER_OF_THREADS, 
		N_TYPE_INT, (void *)&num, sizeof(N_TYPE_INT));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to set thread number(result = %d)", result);
		return false;
	}

	apLog::print(0, apLog::info, " set thread number to %d", num);
	return true;
}

bool apSSEngine1::GetThreadNum(int *pNum)
{
	NResult result;

	result = NObjectGetParameterEx(m_hSE, SEP_NUMBER_OF_THREADS, 
		N_TYPE_INT, (void *)pNum, sizeof(N_TYPE_INT));
	if(NFailed(result))
	{
		apLog::print(0, apLog::error, "failed to get thread number(result = %d)", result);
		return false;
	}

	return true;
}
